<?php

require_once("finefs/class.FineFS.php");
require_once("finefs/utils/except.ApplicationException.php");
require_once("finefs/utils/except.IOException.php");
require_once("class.FineDBCollection.php");
require_once("class.FineDBProtoCollection.php");

/**
 * Main FineDB management object.
 *
 * @author	Amaury Bouchard <amaury.bouchard@finemedia.fr>
 * @copyright	Copyright (c) 2010, FineMedia
 * @package	FineDB
 * @subpackage	lib
 * @version	$Id: class.FineDB.php 8 2011-09-26 10:38:52Z amaury.bouchard $
 */
class FineDB {
	/** Name of the current base. */
	private $_base = null;
	/** FineFS object. */
	private $_finefs = null;
	/** Path on FineFS for this database. */
	private $_path = null;

	/* **************** UTILITY METHODS **************** */
	/**
	 * Create an hexatrigesimal (base 36) representation of a MD5 hash.
	 * For information: 2^128 = 3.4 * 10^38 ; 2^256 = 10^77 ; 10^80 atoms in the univers
	 * @param	string	$str	(optional) String to hash. Randomly generate by default.
	 * @return	string	The resulting string. Variable length (25 characters maximum).
	 */
	static public function hash($str=null) {
		$str = empty($str) ? (time() . mt_rand() . mt_rand() . mt_rand() . mt_rand()) : $str;
		return (base_convert(md5($str), 16, 36));
	}
	/* **************** CONSTRUCTION METHODS ******************* */
	/**
	 * Constructor.
	 * @param	string	$base	Name of the base to use.
	 * @throws	ApplicationException	Base name error.
	 */
	public function __construct($base) {
		if (!is_string($base) || strlen($base) < 2)
			throw new ApplicationException("Bad base name.", ApplicationException::API);
		$this->_base = $base;
		$this->_finefs = FineFS::factory();
		$this->_path = "finedb/" . rawurlencode($base);
	}

	/* *********************** GETTERS METHODS ********************** */
	/**
	 * Returns the FineFSobject.
	 * @return	FineFS	The FineFS object.
	 */
	public function getFineFS() {
		return ($this->_finefs);
	}
	/**
	 * Returns the path on FineFS for this database.
	 * @return	string	The path.
	 */
	public function getPath() {
		return ($this->_path);
	}

	/* *********************** COLLECTION METHODS ******************* */
	/**
	 * Create a new collection.
	 * @param	string	$name			Name of the collection.
	 * @param	array	$indexes		List of metadata to index.
	 * @param	array	$mandatory		List of  mandatory metadata.
	 * @param	string	$collectionObjectName	(optional) Name of the object type for the collection.
	 * @return	FineDBCollection	An object to manage the new collection.
	 * @throws	ApplicationException	Bad parameter.
	 * @throws	IOException		Existing collection, or problem during collection creation.
	 */
	public function createCollection($name, $indexes, $mandatory, $collectionObjectName=null) {
		// check parameters
		if (!is_string($name) || strlen($name) < 2 || !is_array($indexes) || !is_array($mandatory))
			throw new ApplicationException("Bad parameter.", ApplicationException::API);
		// search for a previous collection definition
		$path = $this->_path . "/" . rawurlencode($name) . "/definition";
		try {
			$info = $this->_finefs->getInfo($path);
		} catch (Exception $e) { }
		if ($info)
			throw new IOException("Collection '$name' already exists.", IOException::UNREADABLE);
		// create new collection definition
		$data = array(
			"index"		=> $indexes,
			"mandatory"	=> $mandatory
		);
		$this->_finefs->putData($path, json_encode($data));
		// create a new collection object
		if (!is_subclass_of($collectionObjectName, "FineDBCollection"))
			$collectionObjectName = "FineDBProtoCollection";
		$collection = new $collectionObjectName($this, $name, $indexes, $mandatory);
		return ($collection);
	}
	/**
	 * Fetch a collection.
	 * @param	string	$name			Name of the collection.
	 * @param	string	$collectionObjectName	(optional) Name of the object type for the collection.
	 * @return	FineDBCollection	An object to manage the new collection.
	 * @throws	IOException	Problem to get the collection.
	 */
	public function getCollection($name, $collectionObjectName=null) {
		// retreive collection definition
		$path = $this->_path . "/" . rawurlencode($name) . "/definition";
		$data = $this->_finefs->getData($path);
		$data = json_decode($data['data'], true);
		// create a collection object
		if (!@is_subclass_of($collectionObjectName, "FineDBCollection"))
			$collectionObjectName = "FineDBProtoCollection";
		$collection = new $collectionObjectName($this, $name, $data['index'], $data['mandatory']);
		return ($collection);
	}
}

?>
